package com.zhixun.zhlq.controller.wx;

import com.alibaba.fastjson.JSONObject;

import com.zhixun.zhlq.controller.BaseController;
import com.zhixun.zhlq.entity.SysUserEntity;
import com.zhixun.zhlq.entity.vo.LoginUser;
import com.zhixun.zhlq.service.SysLogsService;
import com.zhixun.zhlq.service.SysUserService;
import com.zhixun.zhlq.shiro.CustomToken;
import com.zhixun.zhlq.shiro.LoginType;
import com.zhixun.zhlq.utils.BsResult;
import com.zhixun.zhlq.utils.HttpClientUtil;
import com.zhixun.zhlq.utils.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;

/**
 * @author eollse-wj
 * @ClassName LoginController
 * @date 2020/7/21
 * @description
 */
@RestController
@Slf4j
@RequestMapping("/weChat")
public class WxLoginController extends BaseController {

    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysLogsService sysLogsService;

    @Value("${wx.app-id}")
    private String weChatAppId;
    @Value("${wx.app-secret}")
    private String weChatAppSecret;

    @Value("${http-proxy.ip}")
    private String httpProxyIp;
    @Value("${http-proxy.port}")
    private Integer httpProxyPort;

    private static final String ERROR_CODE = "errcode";
    /**
     *
     */
    private static final int EXPIRE_CODE = 42001;

    /**
     * 微信公众号授权登录
     *
     * @param request
     * @param code
     * @return
     */

    @PostMapping("/login")
    @ApiOperation(value = "微信公众号授权登录", notes = "微信公众号授权登录")
    @ApiImplicitParam(name = "code", value = "微信公众号获取的code", required = true)
    public BsResult loginByWeChat(HttpServletRequest request, @RequestParam String code) {
        try {
            // 登录凭证不能为空
            if ("".equals(code.trim())) {
                log.error("登录凭证code为空");
                return BsResult.error("登录凭证code不能为空");
            }
            //通过code查询是否已登录过
            SysUserEntity hasLoginUser = sysUserService.getByCode(code);
            HttpClientUtil httpClient = new HttpClientUtil();
            if (hasLoginUser != null) {
                String openId = hasLoginUser.getOpenId();
                return getUserInfo(request, httpClient, openId, code, hasLoginUser.getWeChatAccessToken(), hasLoginUser.getWeChatRefreshToken(), hasLoginUser);
            } else {
                String accessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + weChatAppId + "&secret=" + weChatAppSecret + "&code=" + code + "&grant_type=authorization_code";
                String result = httpClient.get(accessTokenUrl, "UTF-8", null, httpProxyIp, httpProxyPort);
                log.info("登录凭证access_token校验：" + result);
                if (!StringUtil.isEmpty(result)) {
                    JSONObject json = JSONObject.parseObject(result);
                    if (!StringUtil.isEmpty(json.getString(ERROR_CODE))) {
                        return BsResult.error(result);
                    }
                    //access_token接口调用凭证超时时间，单位（秒）
                    String access_token = json.getString("access_token");
                    String refresh_token = json.getString("refresh_token");
                    //用户唯一标识，请注意，在未关注公众号时，用户访问公众号的网页，也会产生一个用户和公众号唯一的OpenID
                    String openId = json.getString("openid");
                    return getUserInfo(request, httpClient, openId, code, access_token, refresh_token, null);
                }
            }
            log.error("登录失败");
            return BsResult.error();
        } catch (Exception e) {
            e.printStackTrace();
            return BsResult.error500();
        }
    }

    private BsResult getUserInfo(HttpServletRequest request, HttpClientUtil httpClient, String openId, String code,
                                 String access_token, String refresh_token, SysUserEntity hasLoginUser) {
        //获取用户信息
        String getUserUrl ="https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + openId + "&lang=zh_CN";
        String userResult = httpClient.get(getUserUrl, "UTF-8", null, httpProxyIp, httpProxyPort);
        log.info("微信登录获取用户[" + openId + "]信息：" + userResult);
        if (!StringUtil.isEmpty(userResult)) {
            JSONObject userJson = JSONObject.parseObject(userResult);
            if (!StringUtil.isEmpty(userJson.getString(ERROR_CODE))) {
                //刷新access_token过期
                if (EXPIRE_CODE == userJson.getInteger(ERROR_CODE)) {
                    //刷新access_token
                    String refreshTokenUrl = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=" + weChatAppId + "&grant_type=refresh_token&refresh_token=" + refresh_token;
                    String refreshTokenResult = httpClient.get(refreshTokenUrl, "UTF-8", null, httpProxyIp, httpProxyPort);
                    log.info("登录凭证refresh_token校验：" + refreshTokenResult);
                    JSONObject refreshTokenJson = JSONObject.parseObject(refreshTokenResult);
                    if (!StringUtil.isEmpty(refreshTokenJson.getString(ERROR_CODE))) {
                        return BsResult.error(refreshTokenResult);
                    }
                    //超时时间，单位（秒）,有30天
                    access_token = refreshTokenJson.getString("access_token");
                    getUserUrl ="https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + openId + "&lang=zh_CN";
                    userResult = httpClient.get(getUserUrl, "UTF-8", null,httpProxyIp, httpProxyPort);
                    log.info("微信登录获取用户[" + openId + "]信息：" + userResult);
                    if (!StringUtil.isEmpty(userResult)) {
                        userJson = JSONObject.parseObject(userResult);
                        if (!StringUtil.isEmpty(userJson.getString(ERROR_CODE))) {
                            return BsResult.error(userResult);
                        }
                    } else {
                        return BsResult.error("请求refresh_token接口异常！");
                    }
                } else {
                    return BsResult.error(userResult);
                }
            }
            String nickName = userJson.getString("nickname");
            int sex = userJson.getInteger("sex");
            String headImgUrl = userJson.getString("headimgurl");
            SysUserEntity user;
            boolean isUpdate = false;
            if (hasLoginUser != null) {
                isUpdate = true;
                user = hasLoginUser;
            } else {
                user = sysUserService.getByOpenId(openId);
                if (user != null) {
                    isUpdate = true;
                    if (user.getStatus() == 0) {
                        return BsResult.error("账号被锁定！");
                    }
                } else {
                    //注册用户(此处将openId存入username，用于shiro登录)
                    user = new SysUserEntity(openId,openId, nickName, headImgUrl, sex, code, access_token, refresh_token);
                    boolean b = sysUserService.save(user);
                    if (user.getId() != null) {
                        saveLogs(setLogs(request, "wx-register", "微信用户【" + nickName + "】注册", user.getId(), nickName));
                    }
                }
            }
            if (isUpdate) {
                //更新用户
                user.setNickName(nickName);
                user.setPicurl(headImgUrl);
                user.setSex(sex);
                user.setWeChatCode(code);
                user.setWeChatAccessToken(access_token);
                user.setWeChatRefreshToken(refresh_token);
                sysUserService.updateById(user);
            }
            log.info(user.getOpenId() + "：" + user.getNickName() + " login success!");

            //shiro登录
            // 根据用户名（openId）获取token
            CustomToken token = new CustomToken(openId,"",true,null, LoginType.NOPASSWORD);
            // 获取 subject 认证主体
            Subject subject = SecurityUtils.getSubject();
            try{
                // 开始认证，这一步会跳到我们自定义的 Realm 中
                subject.login(token);
                SysUserEntity principal = (SysUserEntity) subject.getPrincipal();
                //添加登录日志
                sysLogsService.add(request, "wx_login", "登录了系统！", principal.getId(), principal.getNickName());
                principal.setPassword(null);
                return BsResult.success(principal);
            }catch(AuthenticationException e){
                throw new AuthenticationException("用户名或密码错误！");
            }
        } else {
            log.error("微信授权-openid-[" + openId + "]获取用户信息异常");
            return BsResult.error("微信授权获取用户信息失败");
        }
    }

}

